package com.greyu.ysj.service.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Future;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import com.greyu.ysj.config.Constants;
import com.greyu.ysj.utils.InvestFlag;
import com.greyu.ysj.entity.CbtInvest;
import com.greyu.ysj.entity.CbtInvitedIncome;
import com.greyu.ysj.entity.CbtStarLevel;
import com.greyu.ysj.entity.CbtUserStar;
import com.greyu.ysj.entity.CbtUserUpdate;
import com.greyu.ysj.entity.InvTree;
import com.greyu.ysj.entity.User;
import com.greyu.ysj.mapper.UserMapper;
import com.greyu.ysj.service.CbtInvestService;
import com.greyu.ysj.service.CbtInvitedIncomeService;
import com.greyu.ysj.service.CbtStarLevelService;
import com.greyu.ysj.service.CbtUserStarService;
import com.greyu.ysj.service.CbtUserUpdateMapperService;
import com.greyu.ysj.service.InvTreeService;
import com.greyu.ysj.service.InvitationTreeService;
import com.greyu.ysj.service.UserService;
import com.greyu.ysj.utils.FindKthElements;
import com.greyu.ysj.utils.NodeItem;

@Service
public class InvitationTreeServiceImpl implements InvitationTreeService {
	@Autowired
	private UserService userService;
	@Autowired
	private CbtInvestService cbtInvestService;
	@Autowired
	private UserMapper userMapper;
	
	@Autowired
	private InvTreeService invTreeService;
	@Autowired
	private CbtInvitedIncomeService cbtInvitedIncomeService;
	
	@Autowired
	private CbtStarLevelService cbtStarLevelService;
	@Autowired
	private CbtUserUpdateMapperService cbtUserUpdateMapperService;
	
	@Autowired
	private CbtUserStarService cbtUserStarService;
	
	
	//遍历生成所有的树
	@Override
	public void createNodeList( Integer index, Integer maxLevel) {
		// TODO Auto-generated method stub
		List<InvestFlag> investList = new ArrayList<>();
		//查询出所有的一级
//		User user = new User();
//        user.setReferer(0);
        List<User> users = userService.selectUsersListbyUserId(0);
        if (users.size()>0) {
        	Map<Integer, Integer> processMap = new HashMap<Integer, Integer>();
    		
    			//进行更新数据的状态--正在处理中
    			//进行计算每个根节点的信息
    			//获取该用户的推荐树
    			
    			
        	users.stream().forEach(u->{
        		
        		Integer rootUserId = this.findRootID(u.getUserId());
//    			if (processMap.containsKey(rootUserId)==false) {
    				NodeItem root = new NodeItem();
                    root.setRoot(true);
                    root.setCreatFlag(false);
                    root.setLevelIndex(1);
                    root.setUserId(u.getUserId());
                    root.setUserPhone(u.getPhone());
                    int maxLevels = 15;
                    
//                    processMap.put(rootUserId, rootUserId);
                    createList(root, index, maxLevel,investList);
                    try {
						processRecommandTree(root,true,u);
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
//                    
                    if (investList.size() >0) {
        	        	this.cbtInvestService.updateBatch(investList);
    			} 
        	});	
		}	
	}
	
	//遍历生成一支的树
		@Override
		public void createOneNodeList(User user, Integer index, Integer maxLevel) {

			        List<InvestFlag> investList = new ArrayList<>();
	                Map<Integer, Integer> processMap = new HashMap<Integer, Integer>();
	        			//进行计算每个根节点的信息
	        			//获取该用户的推荐树
	        			Integer rootUserId = this.findRootID(user.getUserId());
//	        			if (processMap.containsKey(rootUserId)==false) {
	        			
	        				NodeItem root = new NodeItem();
	    	                root.setRoot(true);
	    	                root.setCreatFlag(false);
	    	                root.setLevelIndex(1);
	    	               
							User lists = userService.selectUserById(rootUserId);
							root.setUserId(rootUserId);
		 	    	        root.setUserPhone(lists.getPhone());
							
	    	               
	    	                int maxLevels = 1000;
	    	                
//	    	                processMap.put(rootUserId, rootUserId);
	    	                createList(root, index, maxLevel,investList);
	    	                System.out.println("***********************************************************************");
	    	                try {
								processRecommandTree(root,true,user);
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
	    	                if (investList.size() >0) {
	            	        	this.cbtInvestService.updateBatch(investList);
	            			}
	    	                System.out.println("----------------------------------------------------=======");
//	        			}
		}
		
	
		
	private void createList(NodeItem nodeItem ,Integer index, Integer maxLevel,List<InvestFlag> investList) {

		nodeItem.setCreatFlag(true);
		nodeItem.setLevelIndex(index);
        
         //查询直属推荐
//         User user1 = new User();
//         user1.setReferer(nodeItem.getUserId());
         List<User> users1 = userService.selectUsersListbyUserId(nodeItem.getUserId());
         Integer referCnt =  users1.size();
         nodeItem.setReferCnt(referCnt);
         //获取用户所有投资数据
//         Double assetInvest = this.cbtInvestService.selectTotalInvestByuserId(nodeItem.getUserId())/Constants.AKB_INVEST_RATIO;
         Double assetInvest = this.cbtInvestService.selectTotalInvestByuserId(nodeItem.getUserId());
         nodeItem.setAssetInvest(assetInvest);
       //获取当前用户所有参与返还的用户投资额度
//         Double assetValidInvest = this.cbtInvestService.selectTotalUnExtractInvestByuserId(nodeItem.getUserId())/Constants.AKB_INVEST_RATIO;
         Double assetValidInvest = this.cbtInvestService.selectTotalUnExtractInvestByuserId(nodeItem.getUserId());
         nodeItem.setAssetValidInvest(assetValidInvest);
         List<CbtInvest> investsList= this.cbtInvestService.getAllValidInvestListByUserId(nodeItem.getUserId());
	        for (CbtInvest cbtInvest : investsList) {
	        	InvestFlag flags = new InvestFlag();
	        	flags.setId(cbtInvest.getId());
	        	flags.setFlag(1);
				investList.add(flags);
			}
         
      //添加所有的直属子类
         LinkedList<NodeItem> chLinkedList = new LinkedList<>();
        if (users1.size()>0) {
        	Integer indexx = index;
        	users1.stream().forEach(us->{
        		 NodeItem childItem = new NodeItem();
	             childItem.setCreatFlag(false);
	             childItem.setUserId(us.getUserId());
	             childItem.setLevelIndex(indexx + 1);
	             childItem.setUserPhone(us.getPhone());
	             chLinkedList.add(childItem);
        	});
			
		}
        nodeItem.setChildList(chLinkedList);
        
        index++;
        if (index < maxLevel) {
            for (NodeItem child : chLinkedList) {
            	createList(child, index, maxLevel,investList);
            }
        }
        
      //计算用户星级
        LinkedList<NodeItem> temNode = nodeItem.getChildList();
        int teamCnt = temNode.size();
        /**
         * 计算资产
         */
        double validTeamValid = 0.0;
        double teamAsset = 0.0;    
        /*
         * 思想如下,首先进行获取所有团队中的最小星级,因为该节点多能够比团对中最小星级上进行平滑升一级;
         * 所有团队中最大值中的最小值
         */
        int minStarLevel = Constants.USER_LEVEL_STAR_DEFAULT;
        int maxStarLevel = Constants.USER_LEVEL_STAR_DEFAULT;
        boolean isfirst = true;

        int []startArray =null;
        int arrayLen = temNode.size();
        startArray = new int[arrayLen];
        int i = 0;
        for (NodeItem nodeItem2 : temNode) {
        	//进行截取操作
        	//如果当前节点是叶子节点，直接将该节点的投资额度，添加到上一个节点的团队业绩中
	        if (nodeItem.getReferCnt() == 0) {
	        	teamAsset += nodeItem2.getAssetInvest();
				validTeamValid += nodeItem2.getAssetValidInvest();
				//如果该节点不是叶子节点
				//如果该节点的星级小于父节点
				//或者该节点的星级为0，则将该节点的团队业绩以及该节点的投资额度都添加父节点的团队业绩中
	        }else/* if (nodeItem3.getUserStar() < userStarLevel || nodeItem3.getUserStar() == 0) */{
	        	teamAsset +=nodeItem2.getTeamAssetInvest();
	        	teamAsset +=nodeItem2.getAssetInvest(); 
	        	validTeamValid += nodeItem2.getTeamAssetValidInvest();
	        	validTeamValid +=nodeItem2.getAssetValidInvest();
	        }
	        //计算星级
			if (isfirst) {
				minStarLevel = nodeItem2.getTeamMaxStar();
				maxStarLevel = nodeItem2.getTeamMaxStar();
			}else {
				isfirst = false;
				minStarLevel = (minStarLevel >= nodeItem2.getTeamMaxStar())?nodeItem2.getTeamMaxStar():minStarLevel;
				maxStarLevel = (maxStarLevel >= nodeItem2.getTeamMaxStar())?maxStarLevel : nodeItem2.getTeamMaxStar();
			}
			startArray[i++]=nodeItem2.getTeamMaxStar();
		}
        nodeItem.setTeamAssetInvest(teamAsset);
        nodeItem.setTeamAssetValidInvest(validTeamValid); 
        //如果数组大于3的时候进行通过算法获取第三大数据
        if (arrayLen >=Constants.START_TEAM_NUM) {
        	//System.out.println("startArray:"+startArray);
            //获取第三高的level
            FindKthElements fke = new FindKthElements();
    		List<Integer> res = fke.findKthElements(startArray, 2);
    		//System.out.println("max top 3===>:"+res);
    		if (res.size()>0) {
    			minStarLevel = res.get(res.size()-1);
    		}
    		//System.out.println("the top 3===>:"+minStarLevel);
		}
        //System.out.println("===>>>>>>>>minStarLevel="+minStarLevel);
        //System.out.println("===>>>>>>>>nodeItem.getTeamAssetInvest()="+nodeItem.getTeamAssetInvest());
		//进行计算当前节点的level
        double selectTotalInvestByuserId = cbtInvestService.selectTotalInvestByuserId(nodeItem.getUserId());
        
//        double totalInvited=this.cbtInvestService.selectAllInvestByuserId(nodeItem.getUserId())/Constants.AKB_INVEST_RATIO;
        double totalInvited=this.cbtInvestService.selectAllInvestByuserId(nodeItem.getUserId());
        
        int userStarLevel = Constants.USER_LEVEL_STAR_DEFAULT;	//0 
        //如过团队业绩小于500000，用户为0级
        if (nodeItem.getTeamAssetInvest() < Constants.START_ASSET_1 ||  totalInvited <100000 || selectTotalInvestByuserId<5000 ) //500000
        {
        	userStarLevel = Constants.USER_LEVEL_STAR_DEFAULT;// 0
        	//如果团队业绩小于5000000 直属邀请大于3   用户为1级
        } else if (nodeItem.getTeamAssetInvest() < Constants.START_ASSET_2 && //5000000
        		teamCnt >= Constants.START_TEAM_CNT_2 && totalInvited >=100000 && selectTotalInvestByuserId>=5000) { //3
        	userStarLevel = Constants.USER_LEVEL_STAR_1; //1
        	//用户等级小于等于最小级+1  用户等级为最小级+1
        	if (userStarLevel >= minStarLevel+1) {
        		userStarLevel = minStarLevel+1;
        	}//团队业绩小于50000000 直属邀请大于3 用户等级为2
        } else if (nodeItem.getTeamAssetInvest() < Constants.START_ASSET_3 && // 50000000.0
        		teamCnt >= Constants.START_TEAM_CNT_3 && selectTotalInvestByuserId>=5000 ){  //3
        	userStarLevel = Constants.USER_LEVEL_STAR_2; //2
        		if (userStarLevel >= minStarLevel+1) {
        		userStarLevel = minStarLevel+1;
        	}
        	//团队业绩小于200000000 直属邀请大于3 用户等级为3
		} else if (nodeItem.getTeamAssetInvest() < Constants.START_ASSET_4 && //200000000
        		teamCnt >= Constants.START_TEAM_CNT_4 && selectTotalInvestByuserId>=5000 ) { //3
			userStarLevel = Constants.USER_LEVEL_STAR_3; //3
			if (userStarLevel >= minStarLevel+1) {
        		userStarLevel = minStarLevel+1;
        	}
			//团队业绩小于500000000 直属邀请大于3 用户等级为4
		} 
		else if (nodeItem.getTeamAssetInvest() < Constants.START_ASSET_5&& //500000000
        		teamCnt >= Constants.START_TEAM_CNT_5  && selectTotalInvestByuserId>=5000) { //3
			userStarLevel = Constants.USER_LEVEL_STAR_4; //4
			if (userStarLevel >= minStarLevel+1) {
        		userStarLevel = minStarLevel+1;
        	}
			//团队业绩大于500000000 直属邀请大于3 用户等级为5
		} else if (nodeItem.getTeamAssetInvest() >= Constants.START_ASSET_5 && //500000000
        		teamCnt >= Constants.START_TEAM_CNT_5 && selectTotalInvestByuserId>=5000 ) { //3
			userStarLevel = Constants.USER_LEVEL_STAR_5; //5
			if (userStarLevel >= minStarLevel+1) {
        		userStarLevel = minStarLevel+1;
        	}
		}	 
        CbtUserStar selectAllByUserId = cbtUserStarService.selectAllByUserId(nodeItem.getUserId());
        if (selectAllByUserId!=null) {
        	
			Integer userStarLevel1 = selectAllByUserId.getAccount();
			if (userStarLevel<userStarLevel1) {
				userStarLevel = userStarLevel1;
			}
		}
        nodeItem.setUserStar(userStarLevel);
//        System.out.println(nodeItem.getUserId()+"用户星级3"+nodeItem.getUserStar());
        nodeItem.setTeamMaxStar(userStarLevel>maxStarLevel?userStarLevel:maxStarLevel);
        
        InvTree invTree =  new InvTree();
		invTree.setUserId(nodeItem.getUserId());
        invTree.setUserphone(nodeItem.getUserPhone());
        invTree.setAssetInvest(assetInvest);
        invTree.setAssetValidInvest(assetValidInvest);
        invTree.setIsCreatFlag("true");
        invTree.setLevelIndex(index);
        invTree.setReferCnt(referCnt);
        invTree.setRoot("true");
        invTree.setTeamAssetInvest(teamAsset);
        invTree.setTeamAsssetValidInvest(validTeamValid);
        invTree.setTeamMaxStar(userStarLevel>maxStarLevel?userStarLevel:maxStarLevel);
        
        invTree.setUserStar(userStarLevel);
        
//        System.out.println(nodeItem.getUserId()+"用户星级4"+invTree.getUserStar());
       InvTree invTrees =  invTreeService.selectInvTreebyUserId(nodeItem.getUserId());
       if (invTrees==null) {
    	   invTreeService.save(invTree);
	}else{
		invTreeService.updateInvTreebyUserId( invTree);
	}
       
       System.out.println("=========================================="+nodeItem.getUserId());
         
	}
	
	/**
	 * 进行查找用户的祖先节点
	 */
	public Integer findRootID(Integer userId) {
		// TODO Auto-generated method stub
		Integer rootId = userId;
		User userNode =  this.userMapper.selectByPrimaryKey(userId);
		if (null == userNode) {
			return rootId;
		}
		Integer parendId = userNode.getReferer();
		while (parendId !=null) {
			if (0 == parendId) {
				return rootId;	//这是当前父类顶节点ID
			}
			rootId = parendId;
			User tmp = this.userMapper.selectByPrimaryKey(parendId);
//			if (null == tmp) {
//				return rootId;	//这是当前父类顶节点ID
//			}
			parendId = tmp.getReferer();
			
		}
		return rootId;
	}
	
	private void processRecommandTree(NodeItem root,boolean flag,User user) throws IOException {
		//处理推荐收益信息
		if (flag) {
			processRecommandByNode(root,user);
		}
		LinkedList<NodeItem> tmpItem = root.getChildList();
		for (NodeItem nodeItem : tmpItem) {
			processRecommandTree(nodeItem,flag,user);
		}
	}
	
	/**
	 * 进行根据根节点进行计算每一个节点的推荐值和数据和构建用户的推荐信息
	 */
	private void processRecommandByNode(NodeItem root,User user) {
		
        Integer memberId = root.getUserId();
        int count = this.cbtInvestService.countInvestsByuserId(memberId);
		if (0 == count) {
			return;
		}
		int incomeCnt = this.cbtInvitedIncomeService.countByuserId(memberId.intValue());
		LinkedList<NodeItem> tmpItem = root.getChildList();
		//添加计算逻辑
		//进行判断该用户是否需要进行计算推荐奖励
        //直推收益
        {
        	//根据用户等级,进行获取每一个星级的抽成比例
        	int rootStar = root.getUserStar();
        	CbtStarLevel cbtStarLevel = this.cbtStarLevelService.selectUserStarLevelByStar(rootStar);
        	//如果获取失败,该次不做结算
        	if (null == cbtStarLevel) {
        		return;
        	}
        	for (NodeItem tmp : tmpItem) {
        		//计算直接推荐奖励
				double directInvestAsset = (incomeCnt == 0)? tmp.getAssetInvest():tmp.getAssetValidInvest();
				double referIncome = directInvestAsset* cbtStarLevel.getDirectRatio();
				//进行更新数据库
				if ( referIncome > 0) {
					CbtInvitedIncome cbtInvitedIncome =new CbtInvitedIncome();
					cbtInvitedIncome.setUserId(memberId.intValue());
					cbtInvitedIncome.setRegisterNo(tmp.getUserId());
					cbtInvitedIncome.setCreateDate(new Date());
					cbtInvitedIncome.setInvestId(-1);
					cbtInvitedIncome.setAmount(referIncome);
					cbtInvitedIncome.setFlag(0);
					this.cbtInvitedIncomeService.save(cbtInvitedIncome);
				}
				
			}
        }
       
		//---------------------
		//计算团队收益奖励
//        Map<Integer, Double> map = this.userService.getRewardValue(root,root.getUserStar(),incomeCnt == 0,true);
		double referteamIncome = this.userService.getRewardValue(root,root.getUserStar(),0,true);
		BigDecimal decimal = new BigDecimal(Double.toString(referteamIncome));
        System.out.println(decimal);
        BigDecimal number = decimal.setScale(4, BigDecimal.ROUND_DOWN).stripTrailingZeros();
        referteamIncome =  number.doubleValue();
//        double referteamIncome = this.userService.getRewardValue(root,root.getUserStar(),incomeCnt == 0,true,0,true);
		if (referteamIncome>0) {
			CbtInvitedIncome cbtTeamInvitedIncome =new CbtInvitedIncome();
			cbtTeamInvitedIncome.setUserId(memberId.intValue());
			cbtTeamInvitedIncome.setRegisterNo(user.getUserId());
			cbtTeamInvitedIncome.setCreateDate(new Date());
			cbtTeamInvitedIncome.setInvestId(-1);
			cbtTeamInvitedIncome.setAmount(referteamIncome);
			cbtTeamInvitedIncome.setFlag(1);
			this.cbtInvitedIncomeService.save(cbtTeamInvitedIncome);
		}
		
		
		
		
	}
	
	
	 public static Random random =new Random();  
	  
	    @Async  
	    public void doTaskOne() {
	    	List<CbtUserUpdate> selectUpdateByStatus = cbtUserUpdateMapperService.selectUpdateByStatus(1);
	    	if (selectUpdateByStatus.size() > 0) {
	    		
			} else {
				invtree();			
			}
	    }  
	    
	    public synchronized void invtree() {
			doTask();//执行
			List<CbtUserUpdate> sss2 = cbtUserUpdateMapperService.selectUpdateByStatus(2);
			if (sss2.size() > 0) {
				invtree();	
			}		
		}
	    
	    /**
	     * 执行方法
	     */
	    public synchronized void doTask(){
	    	List<CbtUserUpdate> selectPrcessList = cbtUserUpdateMapperService.selectUpdateAll();
			
			selectPrcessList.stream().forEach(ss->{
				//更新缓存表状态为正在运行
				
				cbtUserUpdateMapperService.updateStatus(1, ss.getId());
				//更新投资表状态为已投资计算状态
				cbtInvestService.updateFlag(ss.getInvestId(), 0);

				User user2 = userService.selectByUserId(ss.getMemberId().intValue());
				createOneNodeList(user2, 0, 1000);

				//更新缓存表状态为已结束
				
				cbtUserUpdateMapperService.updateStatus(0, ss.getId());
			});
	    }
	    

}
